A*搜索 - 八数码问题

本文介绍了八数码问题的解决方案,通过问题抽象、图的宽度优先搜索和A*搜索策略,详细阐述如何找到从初始状态到归位状态的路径。A*搜索结合评估函数,提高搜索效率,实现快速求解有解问题,但对无解问题可能需要遍历大量节点,导致运行时间较长。
摘要由CSDN通过智能技术生成

问题描述

八数码问题,简单地来描述是这样的:在一个九宫格内,填有1、2、3、4、5、6、7、8,八个阿拉伯数字,有一个格子为空白。就下面这样,这是一个没有归位的九宫格。

1 2 3
7 8
4 6 5
(未归位的九宫格)

对于上面这个九宫格,我们要通过移动数字来使之归位,每次移动都只能是与空白格相邻的数字移到空白格里面。最终得到归位的九宫格应该是像下面这样的。

1 2 3
8 4
7 6 5
(已归位的九宫格)

我们的目标是,给出一种初始状态,如果有解的话,就把移动的步骤记录(或者输出)下来。值得注意的是,有的初始状态,是无论如何都没有办法使九宫格归位的。


解题思路

问题抽象

对于这个问题,我们不妨这样来看:每一种状态,最多有四种移动方式,也就是说,一种状态最多可以衍生出四种子状态。我们把问题的整体看成一个图,一个状态是图中的一个节点,每个节点生成的自节点由一条有向边来指向。图中总有一个节点的状态是我们要的归位状态,我们要做的就是找到初始节点(即初状态)到这个归位节点的路径。

图的宽度优先搜索

为了找到我们要的路径,我们可以使用宽度优先搜索。我们需要三样东西:集合close,用于保存访问过的节点。集合open,用于保存待访问的节点。每次访问一个节点,就会产生子节点,那么有如下三种情况:

  1. 如果子节点存在于open中,就把该子节点的深度与open中的那个进行对比,若该子节点的深度较小,就替换。

  2. 如果子节点存在于close中,就把该子节点的深度与close中的那个进行对比,若该子节点的深度较小,就替换,并且该子节点的所有后代节点深度都要进行修改。(但是在该问题的A*搜索算法中,我们可以不用考虑这件事。把弱遇到子节点存在于close中的情况,直接将其扔掉就可以了)

  3. 如果子节点不在open中,也不在close,那么将该节点加入到open中等待访问。

如此进行下去,一直到找到我们想要的节点(说明有解),或者open变为空为止(说明无解)

A*搜索

如果问题有解的话,有没有什么办法可以让我们的搜索变得更快呢?
有,我们可以设置一个评估函数F(n) = G(n) + H(n)G(n)给出的是节点的深度。H(n)它给出的是当前状态下将所有数字归位所需的最小步数。每次要从open中取出一个节点的时候,按照F(n)给节点拍一个序,然后选取函数值最小的节点。评估函数H(n)所给出的步数,比实际让九宫格归位所需的步数要少,所以这种启发式搜索叫做A*搜索。


代码实现

我们使用一个整数表示一种状态,整数中的每一位对应了九宫格中的一位,这样可以缩减比较九宫格是否一样所使用的时间。
比如九宫格 :

1 2 3
7 8
6 5 4

被表示为整数123780654。

数据结构

每一个节点里面的信息包含:
state:当前的状态、
prev:父节点的指针、
next:一个存放子节点指针的向量、
cost:H(n)的函数值、
zeropos:空白格子的位置、
depth:节点深度。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

#ifndef NODE_H
#define NODE_H
struct Node{
    int state;
    Node* prev;
    vector<Node*> next;
    int cost;
    int zeropos;
    int dept;
};
#endif
change函数

输入一个状态,以及空白格子的位置,以及空白格子的移动方向,如果移动方向合法,就可以产生子状态,否则返回-1.

int change(int state,int zeropos,int direction){
    int ansstate = 0;
    int usestate = state;
    int zerorow = (zeropos-1)/3;
    int zerocol = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值